<script setup lang="ts">
import { type PropType, computed, ref, watch } from 'vue'
import type { DictClassName, DictProps } from '@idmy/core'
import { appConfig, listDicts } from '@idmy/core'
import { Checkbox, CheckboxGroup, Radio, RadioButton, RadioGroup, Select } from 'ant-design-vue'
import { debounce, isFunction } from 'lodash-es'

defineOptions({ name: 'Dict' })

const props = defineProps({
	buttonStyle: { type: String as PropType<'solid' | 'outline'>, default: 'solid' },
	buttonType: { type: String as PropType<'button' | 'radio'>, default: 'radio' },
	cache: { type: Boolean },
	clazz: { type: String as PropType<DictClassName>, required: true },
	clearable: { type: Boolean, default: true },
	valueKey: { type: String },
	component: { type: String as PropType<'Select' | 'Radio' | 'Checkbox'>, default: 'Select' },
	direction: {
		type: String as PropType<'horizontal' | 'vertical'>,
		default: 'horizontal',
	},
	disabled: Boolean,
	filter: { type: Function as PropType<(item: DictProps) => boolean> },
	modelValue: [String, Number, Array],
	defaultValue: [String, Number, Array],
	multiple: Boolean,
	placeholder: { type: String, default: '请选择' },
})

const emit = defineEmits(['update:modelValue', 'change'])

const dicts = listDicts(props.clazz, undefined, props.cache ?? appConfig.dict.cache)

watch(
	() => props.clazz,
	debounce(clazz => clazz && listDicts(clazz, undefined, props.cache ?? appConfig.dict.cache), 500)
)

const data = computed(() => {
	if (dicts.value.length) {
		const arr = isFunction(props.filter) ? dicts.value.filter(item => props.filter?.(item)) : dicts.value
		let idx = 0
		return arr.map((row: DictProps) => ({
			data: row.data,
			id: row.id,
			key: `${idx++}:${row.value}`,
			label: row.formatName ?? row.name,
			name: row.name,
			// @ts-ignore
			value: row[props.valueKey ?? appConfig.dict.valueKey],
		}))
	} else {
		return []
	}
})

const model = ref<any>(props.defaultValue ?? props.modelValue)
watch(
	() => props.modelValue,
	val => {
		model.value = val
	}
)

const onChange = (val: any) => {
	emit('update:modelValue', val)
	if (val) {
		emit(
			'change',
			dicts.value.find(item => item.value === val)
		)
	} else {
		emit('change', {})
	}
}

const onLoad = (params: any) => {
	listDicts(props.clazz, params, false)
}
defineExpose({ onLoad, data })

const filterOption = (input: string, option: any) => {
	const str = input?.toLowerCase()
	return option?.value?.toLowerCase?.().includes(str) || option?.label?.toLowerCase?.().includes(str)
}
</script>

<template>
	<RadioGroup v-if="component === 'Radio'" v-model:value="model" :disabled="disabled" :button-style="buttonStyle" @change="onChange(model)">
		<template v-if="buttonType === 'button'">
			<RadioButton v-for="item in data" :key="item.key" :value="item.value">
				<slot name="name" v-bind="item">
					{{ item.label }}
				</slot>
			</RadioButton>
		</template>
		<Radio v-for="item in data" v-else :key="item.key" :value="item.value">
			<slot name="name" v-bind="item">
				{{ item.label }}
			</slot>
		</Radio>
	</RadioGroup>
	<CheckboxGroup v-else-if="component === 'Checkbox'" v-model:value="model" :disabled="disabled" @change="onChange(model)">
		<Checkbox v-for="item in data" :key="item.key" :value="item.value">
			<slot name="name" v-bind="item">
				{{ item.label }}
			</slot>
		</Checkbox>
	</CheckboxGroup>
	<Select
		v-else
		v-model:value="model"
		:mode="multiple ? 'multiple' : undefined"
		:disabled="disabled"
		:allow-clear="clearable"
		:placeholder="placeholder"
		show-search
		:options="data"
		:filter-option="filterOption"
		@change="onChange(model)"
	>
		<template #option="item">
			<slot name="name" v-bind="item">
				{{ item.label }}
			</slot>
		</template>
	</Select>
</template>
